﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Marbles.Core.Content.Sites;
using Ionic.Zip;
using System.Web;
using Marbles.Core.Connectors;
using System.Data;
using System.Data.SqlClient;

namespace Marbles.Core.Site
{
    public class Backup
    {

        private SiteDefinition _site = null;

        public Backup(string siteid)
        {
            _site = SiteDefinition.GetSiteBySiteId(siteid);
        }

        public Backup(SiteDefinition Site)
        {
            _site = Site;
        }

        public void Save(string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
            Save(fs);
            fs.Flush();
            fs.Close();
        }

        public void Save(HttpResponse response, string filename)
        {
            response.Clear();
            response.ContentType = "application/zip";
            response.AddHeader("content-disposition", string.Format("attachment;filename={0}.zip", filename));
            Save(response.OutputStream);
            response.Flush();
            response.End();
        }

        public void Save(System.IO.Stream stream)
        {
            using (ZipFile zip = new ZipFile())
            {
                zip.Comment = "Backup of " + _site.Title;
                GenerateScripts(zip);
                SaveResources(zip);
                SaveTemplates(zip);
                SaveTheme(zip);
                zip.Save(stream);
            }
        }

        private string GetFolderPath(string virtualpath)
        {
            string path = virtualpath;
            if (path.StartsWith("~")) { path = path.Substring(1, path.Length - 1); }

            return path;
        }

        protected virtual void SaveTheme(ZipFile zip)
        {
            if (string.IsNullOrEmpty(_site.Theme)) { return; }
            string vpath = string.Format("~/App_Themes/{0}/", _site.Theme);
            string path = HttpContext.Current.Server.MapPath(vpath);
            vpath = string.Format("/App_Themes/{0}/", _site.Theme);

            foreach (string filename in Directory.GetFiles(path, "*.*"))
            {
                zip.AddFile(filename, GetFolderPath(vpath));
            }
        }

        protected virtual void SaveResources(ZipFile zip)
        {
            foreach (string filename in Directory.GetFiles(_site.ApplicationResourceDirectory, "*.*"))
            {
                zip.AddFile(filename, GetFolderPath(_site.ResourceDirectory));
            }
        }

        protected virtual void SaveTemplates(ZipFile zip)
        {
            foreach (string filename in Directory.GetFiles(_site.ApplicationTemplateDirectory, "*.master"))
            {
                zip.AddFile(filename, GetFolderPath(_site.TemplateDirectory));
            }
        }

        protected virtual void GenerateScripts(ZipFile zip)
        {
            StringBuilder sb = new StringBuilder();
            string[] tables = new string[] { "sites", "pages", "banners", "assets", "links", "content", "userformheader", "profiles", "users", "usergrouplink", "userprofiles", "forumcategory", "forumheader", "forumitems" };
            DataConnection dbc = new DataConnection();
            sb.AppendLine("-- Marbles CMS Site Backup Utility");
            sb.AppendLine("-- Database Backup Script");
            sb.AppendLine("-- Script Date : " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString());
            sb.AppendLine("-- ==============================================================");
            sb.AppendLine();
            sb.AppendLine("DECLARE @siteid varchar(40)");
            sb.AppendLine(string.Format("SET @siteid = '{0}'", _site.SiteId));

            foreach (string tbl in tables)
            {
                sb.AppendLine(string.Format("-- Table : {0}", tbl));
                sb.AppendLine(string.Format("DELETE FROM {0} WHERE siteid = @siteid", tbl));
                Command cmd = new Command(string.Format("SELECT * FROM {0} WHERE siteid = @siteid", tbl));
                cmd.AddParameter("@siteid", _site.SiteId);

                DataTable dt = dbc.FetchDataTable(cmd);


                if (dt.Rows.Count <= 0) { sb.AppendLine(); continue; }

                foreach (DataRow dr in dt.Rows)
                {
                    sb.AppendFormat("INSERT INTO {0} ", tbl);
                    for (int i = 0; i < dt.Columns.Count; i++)
                    {
                        sb.Append((i == 0) ? "(" : ", ");
                        sb.AppendFormat("[{0}]", dt.Columns[i].ColumnName);
                    }
                    sb.Append(") VALUES ");
                    for (int i = 0; i < dt.Columns.Count; i++)
                    {
                        sb.Append((i == 0) ? "(" : ", ");
                        sb.Append(GetDataValue(dr[i], dt.Columns[i].DataType));
                    }
                    sb.AppendLine(")");
                }
                sb.AppendLine();
            }

            zip.AddEntry("Database.sql", sb.ToString());
        }


        private string GetDataValue(object value, Type type)
        {
            if (value == null) { return "NULL"; }
            if (value == DBNull.Value) { return "NULL"; }

            switch (type.ToString().ToLower())
            {
                case "system.boolean": return (Convert.ToBoolean(value)) ? "1" : "0";
                case "system.datetime": return string.Format("'{0}'", Convert.ToDateTime(value).ToString("yyyy-MM-dd HH:mm:ss"));
                case "system.string":
                case "system.char": return string.Format("'{0}'", value.ToString().Replace("'", "''"));
            }

            return value.ToString();
        }
    }
}
